
        /*
         * @(#)PopupWindow.java
         *
         * Copyright 2002 - 2003 JIDE Software. All rights reserved.
         */
        package testCode;

//        import com.jidesoft.utils.PortingUtils;

        import javax.swing.*;
        import javax.swing.event.EventListenerList;
        import javax.swing.event.PopupMenuEvent;
        import javax.swing.event.PopupMenuListener;
        import java.awt.*;
        import java.awt.event.*;
        import java.beans.PropertyChangeEvent;
        import java.beans.PropertyChangeListener;
        import java.util.List;
        import java.util.Vector;

        /**
         * PopupWindow class
         * <p/>
         * You can add another JPopupMenu or JComboxBox in this popup.
         * <p/>
         * This class is copied from http://forum.java.sun.com/thread.jsp?forum=57&thread=230866 with some minor modifications.
         */
        public class PopupWindow {

            /**
             * A list of event listeners for this component.
             */
            protected EventListenerList listenerList = new EventListenerList();

            private JWindow _delegate;
            private Container _container;
            private List _grabbed = new Vector();
            private List _excluded = new Vector();
            private WindowListener _windowListener;
            private ComponentListener _componentListener;
            private ContainerListener _containerListener;
            private MouseListener _mouseListener;
            private Component _component;

            // JDK 1.3 Porting Hint.
            // Use AWTEventListener instead
            //    private AWTEventListener _keyEventDispatcher;
            private KeyEventDispatcher _keyEventDispatcher;

            private Component _parent;

            public PopupWindow(Container container) {
                _container = container;
                createDelegate();
                createListeners();
            }

            private void createDelegate() {
                Window window = getWindow();
                if (window != null) {
                    _delegate = new JWindow(window);
                }
            }

            public void add(Component component) {
                _component = component;
                _component.addPropertyChangeListener("preferredSize",
                        new PropertyChangeListener() {
                            public void propertyChange(PropertyChangeEvent evt) {
                                if (_delegate != null) {
                                    _delegate.pack();
                                }
                            }
                        });
                if (_delegate != null) {
                    _delegate.getContentPane().add(component);
                    _delegate.pack();
                    // workaround for a problem. JWindow somehow offset the height by 1
                    // See http://developer.java.sun.com/developer/bugParade/bugs/4511106.html
                    // looks like call pack again solve the problem.
                    _delegate.pack();
                    //                mDelegate.setSize(mDelegate.getSize().width, mDelegate.getSize().height + 1);
                }
            }

            public void show(Component relative, int x, int y) {
                _parent = relative;
                if (_delegate == null) {
                    createDelegate();
                    if (_delegate == null)
                        return;
                    add(_component);
                }

                Point p = new Point(x, y);

                SwingUtilities.convertPointToScreen(p, relative);

//                Rectangle screenSize = PortingUtils.getScreenBounds(relative);
                Rectangle screenSize = new Rectangle(10, 10, 100, 50);

                Dimension size = _component.getPreferredSize();

                int left = p.x + size.width;
                int bottom = p.y + size.height;

                if (p.x < screenSize.x) {
                    p.x = screenSize.x;
                }
                if (left > screenSize.width) {
                    p.x = screenSize.width - size.width;
                }

                if (p.y < screenSize.y) {
                    p.y = screenSize.y;
                }
                if (bottom > screenSize.height) {
                    p.y = screenSize.height - size.height;
                }

                //        Point location = relative.getLocationOnScreen();
                _delegate.setLocation(p.x, p.y);
                _delegate.setSize(_component.getPreferredSize());
                firePopupMenuWillBecomeVisible();
                _delegate.setVisible(true);
                grabContainers();

                // set popup window focus and register esc key
                //        _delegate.toFront();
                //        _delegate.requestFocus();

                // JDK 1.3 Porting Hint
                // Replace by AWTEventListener
                // Following Block is for JDK 1.3
                //        _keyEventDispatcher = new AWTEventListener() {
                //            public void eventDispatched(AWTEvent e) {
                //                if (e instanceof KeyEvent) {
                //                    if (((KeyEvent) e).getKeyCode() == KeyEvent.VK_ESCAPE) {
                //                        hide();
                //                    }
                //                }
                //            }
                //        };
                //        Toolkit.getDefaultToolkit().addAWTEventListener(_keyEventDispatcher, AWTEvent.KEY_EVENT_MASK);

                // Following Block is for JDK 1.4
                _keyEventDispatcher = new KeyEventDispatcher() {
                    public boolean dispatchKeyEvent(KeyEvent e) {
                        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
                            hide();
                            return true;
                        }
                        return false;
                    }
                };
                DefaultFocusManager.getCurrentKeyboardFocusManager()
                        .addKeyEventDispatcher(_keyEventDispatcher);
            }

            public void hide() {
                if (_parent != null) {
                    _parent.requestFocus();
                }
                firePopupMenuWillBecomeInvisible();

                if (_delegate != null) {
                    _delegate.setVisible(false);
                }

                if (_keyEventDispatcher != null) {
                    // JDK 1.3 Porting Hint
                    // Replace by AWTEventListener
                    // Toolkit.getDefaultToolkit().removeAWTEventListener(_keyEventDispatcher);
                    DefaultFocusManager.getCurrentKeyboardFocusManager()
                            .removeKeyEventDispatcher(_keyEventDispatcher);
                    _keyEventDispatcher = null;
                }
                releaseContainers();
                disposeDelegate();
            }

            private void createListeners() {
                _windowListener = new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {
                        hide();
                    }

                    @Override
                    public void windowClosed(WindowEvent e) {
                        hide();
                    }

                    @Override
                    public void windowIconified(WindowEvent e) {
                        hide();
                    }
                };
                _componentListener = new ComponentListener() {
                    public void componentResized(ComponentEvent e) {
                        hide();
                    }

                    public void componentMoved(ComponentEvent e) {
                        hide();
                    }

                    public void componentShown(ComponentEvent e) {
                        hide();
                    }

                    public void componentHidden(ComponentEvent e) {
                        hide();
                    }
                };
                _containerListener = new ContainerListener() {
                    public void componentAdded(ContainerEvent e) {
                        hide();
                    }

                    public void componentRemoved(ContainerEvent e) {
                        hide();
                    }
                };
                _mouseListener = new MouseAdapter() {
                    @Override
                    public void mousePressed(MouseEvent e) {
                        hide();
                    }
                };
            }

            private void disposeDelegate() {
                if (_delegate != null) {
                    _delegate.dispose();
                    _delegate = null;
                }
            }

            private Window getWindow() {
                Container c = _container;
                if (c == null) {
                    return null;
                }
                while (!(c instanceof  Window) && c.getParent() != null)
                    c = c.getParent();
                if (c instanceof  Window)
                    return (Window) c;
                return null;
            }

            private void grabContainers() {
                Container c = _container;
                while (!(c instanceof  Window) && c.getParent() != null)
                    c = c.getParent();
                grabContainer(c);
            }

            private void grabContainer(Container c) {
                if (c instanceof  Window) {
                    ((Window) c).addWindowListener(_windowListener);
                    c.addComponentListener(_componentListener);
                    _grabbed.add(c);
                }

                synchronized (c.getTreeLock()) {
                    int ncomponents = c.getComponentCount();
                    Component[] component = c.getComponents();
                    for (int i = 0; i < ncomponents; i++) {
                        Component comp = component[i];
                        if (!comp.isVisible())
                            continue;
                        if (isExcludedComponent(comp)) {
                            continue;
                        }
                        //                // TODO: this is not the right way to do things. Leave it for future enhancement to popup panel
                        //                // don't hide popup when button of abstract combobox is pressed so that that button can toggle visibility of popup panel
                        //                if(comp instanceof AbstractButton && comp.getParent() instanceof AbstractComboBox) {
                        //                    if(_delegate.isAncestorOf(((AbstractComboBox) comp.getParent()).getPopupPanel())) {
                        //                        continue;
                        //                    }
                        //                }
                        comp.addMouseListener(_mouseListener);
                        _grabbed.add(comp);
                        if (comp instanceof  Container) {
                            Container cont = (Container) comp;
                            if (cont instanceof  JLayeredPane) {
                                cont.addContainerListener(_containerListener);
                            }
                            grabContainer(cont);
                        }
                    }
                }
            }

            void releaseContainers() {
                for (Object o : _grabbed) {
                    Component c = (Component) o;
                    if (c instanceof  Window) {
                        ((Window) c).removeWindowListener(_windowListener);
                        c.removeComponentListener(_componentListener);
                    } else {
                        c.removeMouseListener(_mouseListener);
                    }

                    if (c instanceof  Container) {
                        if (c instanceof  JLayeredPane) {
                            ((Container) c)
                                    .removeContainerListener(_containerListener);
                        }
                    }
                }
                _grabbed.clear();
            }

            /**
             * Gets the visibility of this popup.
             *
             * @return true if popup is visible
             */
            public boolean isVisible() {
                return _delegate != null ? _delegate.isVisible() : false;
            }

            /**
             * Adds a <code>PopupMenu</code> listener which will listen to notification messages from the popup portion of the
             * combo box.
             * <p/>
             * For all standard look and feels shipped with Java 2, the popup list portion of combo box is implemented as a
             * <code>JPopupMenu</code>. A custom look and feel may not implement it this way and will therefore not receive the
             * notification.
             *
             * @param l the <code>PopupMenuListener</code> to add
             * @since 1.4
             */
            public void addPopupMenuListener(PopupMenuListener l) {
                listenerList.add(PopupMenuListener.class, l);
            }

            /**
             * Removes a <code>PopupMenuListener</code>.
             *
             * @param l the <code>PopupMenuListener</code> to remove
             * @see #addPopupMenuListener
             * @since 1.4
             */
            public void removePopupMenuListener(PopupMenuListener l) {
                listenerList.remove(PopupMenuListener.class, l);
            }

            /**
             * Returns an array of all the <code>PopupMenuListener</code>s added to this JComboBox with addPopupMenuListener().
             *
             * @return all of the <code>PopupMenuListener</code>s added or an empty array if no listeners have been added
             *
             * @since 1.4
             */
            public PopupMenuListener[] getPopupMenuListeners() {
                return listenerList.getListeners(PopupMenuListener.class);
            }

            /**
             * Notifies <code>PopupMenuListener</code>s that the popup portion of the combo box will become visible.
             * <p/>
             * This method is public but should not be called by anything other than the UI delegate.
             *
             * @see #addPopupMenuListener
             * @since 1.4
             */
            public void firePopupMenuWillBecomeVisible() {
                Object[] listeners = listenerList.getListenerList();
                PopupMenuEvent e = null;
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
                    if (listeners[i] == PopupMenuListener.class) {
                        if (e == null)
                            e = new PopupMenuEvent(this );
                        ((PopupMenuListener) listeners[i + 1])
                                .popupMenuWillBecomeVisible(e);
                    }
                }
            }

            /**
             * Notifies <code>PopupMenuListener</code>s that the popup portion of the combo box has become invisible.
             * <p/>
             * This method is public but should not be called by anything other than the UI delegate.
             *
             * @see #addPopupMenuListener
             * @since 1.4
             */
            public void firePopupMenuWillBecomeInvisible() {
                Object[] listeners = listenerList.getListenerList();
                PopupMenuEvent e = null;
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
                    if (listeners[i] == PopupMenuListener.class) {
                        if (e == null)
                            e = new PopupMenuEvent(this );
                        ((PopupMenuListener) listeners[i + 1])
                                .popupMenuWillBecomeInvisible(e);
                    }
                }
            }

            /**
             * Notifies <code>PopupMenuListener</code>s that the popup portion of the combo box has been canceled.
             * <p/>
             * This method is public but should not be called by anything other than the UI delegate.
             *
             * @see #addPopupMenuListener
             * @since 1.4
             */
            public void firePopupMenuCanceled() {
                Object[] listeners = listenerList.getListenerList();
                PopupMenuEvent e = null;
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
                    if (listeners[i] == PopupMenuListener.class) {
                        if (e == null)
                            e = new PopupMenuEvent(this );
                        ((PopupMenuListener) listeners[i + 1])
                                .popupMenuCanceled(e);
                    }
                }
            }

            /**
             * PopupWindow will add necessary listeners to some components so that mouse click etc can hide the popup window.
             * However in certain case, you might not want this.
             *
             * @param comp component which will not hide popup when it is clicked.
             */
            public void addAsExcludedComponents(Component comp) {
                if (_excluded.contains(comp)) {
                    return;
                }
                _excluded.add(comp);
            }

            public void removeFromExcludedComponents(Component comp) {
                if (!_excluded.contains(comp)) {
                    return;
                }
                _excluded.remove(comp);
            }

            public boolean isExcludedComponent(Component comp) {
                return _excluded.contains(comp);
            }
        }

